﻿class Socket {
private:
	int _sockfd;
public:
	Socket() :_sockfd(-1) {}
	Socket(int fd) : _sockfd(fd) {}
	~Socket() { Close(); }
	int Fd() { return _sockfd; }
	//创建套接字
	bool Create() {
		// int socket(int domain, int type, int protocol)
		_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (_sockfd < 0) {
			ERR_LOG("CREATE SOCKET FAILED!!");
			return false;
		}
		return true;
	}
	//绑定地址信息
	bool Bind(const std::string& ip, uint16_t port) {
		struct sockaddr_in addr;
		addr.sin_family = AF_INET;
		addr.sin_port = htons(port);
		addr.sin_addr.s_addr = inet_addr(ip.c_str());
		socklen_t len = sizeof(struct sockaddr_in);
		// int bind(int sockfd, struct sockaddr*addr, socklen_t len);
		int ret = bind(_sockfd, (struct sockaddr*)&addr, len);
		if (ret < 0) {
			ERR_LOG("BIND ADDRESS FAILED!");
			return false;
		}
		return true;
	}
	//开始监听
	bool Listen(int backlog = MAX_LISTEN) {
		// int listen(int backlog)
		int ret = listen(_sockfd, backlog);
		if (ret < 0) {
			ERR_LOG("SOCKET LISTEN FAILED!");
			return false;
		}
		return true;
	}
	//向服务器发起连接
	bool Connect(const std::string& ip, uint16_t port) {
		struct sockaddr_in addr;
		addr.sin_family = AF_INET;
		addr.sin_port = htons(port);
		addr.sin_addr.s_addr = inet_addr(ip.c_str());
		socklen_t len = sizeof(struct sockaddr_in);
		// int connect(int sockfd, struct sockaddr*addr, socklen_t len);
		int ret = connect(_sockfd, (struct sockaddr*)&addr, len);
		if (ret < 0) {
			ERR_LOG("CONNECT SERVER FAILED!");
			return false;
		}
		return true;
	}
	//获取新连接
	int Accept() {
		// int accept(int sockfd, struct sockaddr *addr, socklen_t *len);
		int newfd = accept(_sockfd, NULL, NULL);
		if (newfd < 0) {
			ERR_LOG("SOCKET ACCEPT FAILED!");
			return -1;
		}
		return newfd;
	}
	//接收数据
	ssize_t Recv(void* buf, size_t len, int flag = 0) {
		// ssize_t recv(int sockfd, void *buf, size_t len, int flag);
		ssize_t ret = recv(_sockfd, buf, len, flag);
		if (ret <= 0) {
			//EAGAIN 当前socket的接收缓冲区中没有数据了，在⾮阻塞的情况下才会有这
			个错误
				//EINTR 表⽰当前socket的阻塞等待，被信号打断了，
				if (errno == EAGAIN || errno == EINTR) {
					return 0;//表⽰这次接收没有接收到数据
				}
			ERR_LOG("SOCKET RECV FAILED!!");
			return -1;
		}
		return ret; //实际接收的数据⻓度
	}
	ssize_t NonBlockRecv(void* buf, size_t len) {
		return Recv(buf, len, MSG_DONTWAIT); // MSG_DONTWAIT 表⽰当前接收为⾮
		阻塞。
	}
	//发送数据
	ssize_t Send(const void* buf, size_t len, int flag = 0) {
		// ssize_t send(int sockfd, void *data, size_t len, int flag);
		ssize_t ret = send(_sockfd, buf, len, flag);
		if (ret < 0) {
			if (errno == EAGAIN || errno == EINTR) {
				return 0;
			}
			ERR_LOG("SOCKET SEND FAILED!!");
			return -1;
		}
		return ret;//实际发送的数据⻓度
	}
	ssize_t NonBlockSend(void* buf, size_t len) {
		if (len == 0) return 0;
		return Send(buf, len, MSG_DONTWAIT); // MSG_DONTWAIT 表⽰当前发送为⾮
		阻塞。
	}
	//关闭套接字
	void Close() {
		if (_sockfd != -1) {
			close(_sockfd);
			_sockfd = -1;
		}
	}
	//创建⼀个服务端连接
	bool CreateServer(uint16_t port, const std::string& ip = "0.0.0.0",
		bool block_flag = false) {
		//1. 创建套接字，2. 绑定地址，3. 开始监听，4. 设置⾮阻塞， 5. 启动地址重⽤
		if (Create() == false) return false;
		if (block_flag) NonBlock();
		if (Bind(ip, port) == false) return false;
		if (Listen() == false) return false;
		ReuseAddress();
		return true;
	}
	//创建⼀个客⼾端连接
	bool CreateClient(uint16_t port, const std::string& ip) {
		//1. 创建套接字，2.指向连接服务器
		if (Create() == false) return false;
		if (Connect(ip, port) == false) return false;
		return true;
	}
	//设置套接字选项---开启地址端⼝重⽤
	void ReuseAddress() {
		// int setsockopt(int fd, int leve, int optname, void *val, int 
		vallen)
		int val = 1;
		setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&val,
			sizeof(int));
		val = 1;
		setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void*)&val,
			sizeof(int));
	}
	//设置套接字阻塞属性-- 设置为⾮阻塞
	void NonBlock() {
		//int fcntl(int fd, int cmd, ... /* arg */ );
		int flag = fcntl(_sockfd, F_GETFL, 0);
		fcntl(_sockfd, F_SETFL, flag | O_NONBLOCK);
	}
};